package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.PmMaterialItem;
import com.ruoyi.system.domain.PmMaterialList;
import com.ruoyi.system.domain.vo.BudgetGroupVo;
import com.ruoyi.system.enums.MaterialCategoryEnum;
import com.ruoyi.system.mapper.PmMaterialItemMapper;
import com.ruoyi.system.service.IOperationLogService;
import com.ruoyi.system.service.IPmMaterialItemService;
import com.ruoyi.system.service.IPmMaterialListService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service

public class PmMaterialItemServiceImpl  extends ServiceImpl<PmMaterialItemMapper, PmMaterialItem> implements IPmMaterialItemService {


    @Autowired
    private PmMaterialItemMapper materialItemMapper;

    @Autowired
    private IPmMaterialListService materialListService;

    @Autowired
    private IOperationLogService operationLogService;

    @Override
    public IPage<PmMaterialItem> selectMaterialItemPage(int pageNum, int pageSize, Long listId, PmMaterialItem item) {
        Page<PmMaterialItem> page = new Page<>(pageNum, pageSize);
        return materialItemMapper.selectMaterialItemPage(page, listId, item);
    }

    @Transactional
    @Override
    public boolean batchAddItems(Long listId, List<PmMaterialItem> items) {
        if (listId == null || CollectionUtils.isEmpty(items)) {
            throw new ServiceException("清单ID不能为空，且条目列表不可为空");
        }

        // 1. 生成分组ID（同组条目复用group_id）
        Map<String, String> groupNameToIdMap = new HashMap<>();
        for (PmMaterialItem item : items) {
            item.setListId(listId);
            item.setCreateTime(LocalDateTime.now());
            item.setUpdateTime(LocalDateTime.now());
            // 计算用户总价和成本总价
            item.setUserTotalPrice(item.getUserViewPrice().multiply(item.getMaterialQuantity()));
            item.setCostTotalPrice(item.getCostPrice().multiply(item.getMaterialQuantity()));

            // 2. 处理分组：同group_name生成相同group_id
            if (StringUtils.isNotBlank(item.getBudgetGroupName())) {
                String groupId = groupNameToIdMap.get(item.getBudgetGroupName());
                if (groupId == null) {
                    groupId = UUID.randomUUID().toString().replace("-", ""); // 生成唯一组ID
                    groupNameToIdMap.put(item.getBudgetGroupName(), groupId);
                }
                item.setBudgetGroupId(groupId);
            }
        }

        // 3. 批量插入
        int insertCount = materialItemMapper.batchInsertItems(items);
        if (insertCount > 0) {
            // 4. 重新计算清单汇总
            materialListService.calculateListSummary(listId);
            // 5. 记录日志
            operationLogService.saveMaterialLog(
                    listId,
                    "批量添加物料",
                    getCurrentUserId(),
                    getCurrentUserName(),
                    "ITEM_BATCH_ADD",
                    null,
                    "{\"insert_count\":" + insertCount + "}",
                    "批量添加" + insertCount + "条物料条目"
            );
            return true;
        }
        return false;
    }

    @Transactional
    @Override
    public boolean confirmBudgetType(Long itemId, Integer finalBudgetType, Long operatorId, String operatorName) {
        // 1. 参数校验
        if (finalBudgetType == null || !Arrays.asList(1, 2, 3).contains(finalBudgetType)) {
            throw new ServiceException("最终预算类别必须为1（基础项）、2（升级项）、3（增项）");
        }
        PmMaterialItem currentItem = getById(itemId);
        if (currentItem == null) {
            throw new ServiceException("物料条目不存在（ID：" + itemId + "）");
        }
        if (currentItem.getIsBudgetConfirmed() == 1) {
            throw new ServiceException("该物料预算类别已确认，不可重复操作");
        }

        // 2. 同组单选约束：取消组内其他已确认条目
        String groupId = currentItem.getBudgetGroupId();
        if (StringUtils.isNotBlank(groupId)) {
            List<PmMaterialItem> confirmedItems = materialItemMapper.selectConfirmedItemsByGroupId(groupId, itemId);
            if (!CollectionUtils.isEmpty(confirmedItems)) {
                for (PmMaterialItem item : confirmedItems) {
                    item.setIsBudgetConfirmed(0);
                    item.setFinalBudgetType(null);
                    item.setUpdateTime(LocalDateTime.now());
                    updateById(item);

                    // 记录取消确认日志
                    operationLogService.saveMaterialLog(
                            item.getListId(),
                            "物料[" + item.getMaterialName() + "]",
                            operatorId,
                            operatorName,
                            "BUDGET_CONFIRM_CANCEL",
                            "{\"is_budget_confirmed\":1,\"final_budget_type\":" + item.getFinalBudgetType() + "}",
                            "{\"is_budget_confirmed\":0,\"final_budget_type\":null}",
                            "同分组[" + item.getBudgetGroupName() + "]确认新选项，自动取消该条目"
                    );
                }
            }
        }

        // 3. 确认当前条目
        currentItem.setIsBudgetConfirmed(1);
        currentItem.setFinalBudgetType(finalBudgetType);
        currentItem.setUpdateTime(LocalDateTime.now());
        boolean updateResult = updateById(currentItem);

        // 4. 记录日志+重新计算清单汇总
        if (updateResult) {
            String budgetTypeName = getBudgetTypeName(finalBudgetType);
            operationLogService.saveMaterialLog(
                    currentItem.getListId(),
                    "物料[" + currentItem.getMaterialName() + "]",
                    operatorId,
                    operatorName,
                    "BUDGET_CONFIRM",
                    "{\"is_budget_confirmed\":0,\"budget_type\":" + currentItem.getBudgetType() + "}",
                    "{\"is_budget_confirmed\":1,\"final_budget_type\":" + finalBudgetType + "}",
                    "确认预算类别为：" + budgetTypeName
            );
            materialListService.calculateListSummary(currentItem.getListId());
        }
        return updateResult;
    }

    @Override
    public List<BudgetGroupVo> getBudgetGroupListByListId(Long listId) {
        // 1. 查询清单下所有条目
        List<PmMaterialItem> allItems = list(
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<PmMaterialItem>()
                        .eq("list_id", listId)
                        .orderByAsc("material_category", "budget_group_id", "sort_no")
        );
        if (CollectionUtils.isEmpty(allItems)) {
            return new ArrayList<>();
        }

        // 2. 按分组ID聚合
        Map<String, List<PmMaterialItem>> groupMap = allItems.stream()
                .filter(item -> StringUtils.isNotBlank(item.getBudgetGroupId()))
                .collect(Collectors.groupingBy(PmMaterialItem::getBudgetGroupId));

        // 3. 处理未分组条目
        List<PmMaterialItem> noGroupItems = allItems.stream()
                .filter(item -> StringUtils.isBlank(item.getBudgetGroupId()))
                .collect(Collectors.toList());

        // 4. 转换为聚合VO
        List<BudgetGroupVo> groupVoList = new ArrayList<>();

        // 4.1 处理有分组条目
        for (Map.Entry<String, List<PmMaterialItem>> entry : groupMap.entrySet()) {
            List<PmMaterialItem> groupItems = entry.getValue();
            BudgetGroupVo groupVo = new BudgetGroupVo();
            groupVo.setGroupId(entry.getKey());
            groupVo.setGroupName(groupItems.get(0).getBudgetGroupName());
            
            // 设置物料分类信息（取组内第一个条目的分类）
            PmMaterialItem firstItem = groupItems.get(0);
            groupVo.setMaterialCategory(firstItem.getMaterialCategory());
            MaterialCategoryEnum categoryEnum = MaterialCategoryEnum.getByCode(firstItem.getMaterialCategory());
            groupVo.setMaterialCategoryName(categoryEnum != null ? categoryEnum.getDesc() : "未知分类");
            
            groupVo.setItems(groupItems);
            // 查找已确认条目
            groupVo.setConfirmedItem(findConfirmedItem(groupItems));
            groupVoList.add(groupVo);
        }

        // 4.2 处理未分组条目（每个视为独立组）
        for (PmMaterialItem item : noGroupItems) {
            BudgetGroupVo groupVo = new BudgetGroupVo();
            groupVo.setGroupId(null);
            groupVo.setGroupName("未分组选项");
            
            // 设置物料分类信息
            groupVo.setMaterialCategory(item.getMaterialCategory());
            MaterialCategoryEnum categoryEnum = MaterialCategoryEnum.getByCode(item.getMaterialCategory());
            groupVo.setMaterialCategoryName(categoryEnum != null ? categoryEnum.getDesc() : "未知分类");
            
            groupVo.setItems(Collections.singletonList(item));
            groupVo.setConfirmedItem(item.getIsBudgetConfirmed() == 1 ? item : null);
            groupVoList.add(groupVo);
        }

        return groupVoList;
    }

    @Override
    public Map<Integer, List<BudgetGroupVo>> getBudgetGroupListByListIdWithCategorySplit(Long listId) {
        // 1. 先获取原有的预算分组数据
        List<BudgetGroupVo> allGroups = getBudgetGroupListByListId(listId);
        
        if (CollectionUtils.isEmpty(allGroups)) {
            return new HashMap<>();
        }

        // 2. 按物料分类进行分组
        Map<Integer, List<BudgetGroupVo>> categoryGroups = allGroups.stream()
                .collect(Collectors.groupingBy(
                        group -> {
                            // 从组内第一个物料获取分类信息
                            if (group.getItems() != null && !group.getItems().isEmpty()) {
                                return group.getItems().get(0).getMaterialCategory();
                            }
                            return 0; // 默认分类
                        },
                        LinkedHashMap::new, // 保持插入顺序
                        Collectors.toList()
                ));

        return categoryGroups;
    }

    // 辅助方法：获取当前登录用户ID
    private Long getCurrentUserId() {
        return com.ruoyi.common.utils.SecurityUtils.getUserId();
    }

    // 辅助方法：获取当前登录用户名
    private String getCurrentUserName() {
        return com.ruoyi.common.utils.SecurityUtils.getUsername();
    }

    // 辅助方法：预算类别数字转名称
    private String getBudgetTypeName(Integer type) {
        Map<Integer, String> typeMap = new HashMap<>();
        typeMap.put(1, "基础项");
        typeMap.put(2, "升级项");
        typeMap.put(3, "增项");
        return typeMap.getOrDefault(type, "未知类别");
    }

    @Transactional
    @Override
    public boolean updateMaterialItem(PmMaterialItem item, Long operatorId, String operatorName) {
        if (item == null || item.getId() == null) {
            throw new ServiceException("物料条目ID不能为空");
        }

        // 1. 查询原数据用于日志记录
        PmMaterialItem originalItem = getById(item.getId());
        if (originalItem == null) {
            throw new ServiceException("物料条目不存在（ID：" + item.getId() + "）");
        }

        // 2. 校验清单状态（已推送或已确认的清单不允许修改）
        PmMaterialList materialList = materialListService.getById(originalItem.getListId());
        if (materialList != null && materialList.getListStatus() >= 2) {
            throw new ServiceException("清单已推送或已确认，不允许修改物料条目");
        }

        // 3. 重新计算价格
        if (item.getUserViewPrice() != null && item.getMaterialQuantity() != null) {
            item.setUserTotalPrice(item.getUserViewPrice().multiply(item.getMaterialQuantity()));
        }
        if (item.getCostPrice() != null && item.getMaterialQuantity() != null) {
            item.setCostTotalPrice(item.getCostPrice().multiply(item.getMaterialQuantity()));
        }

        // 4. 设置更新时间
        item.setUpdateTime(LocalDateTime.now());

        // 5. 执行更新
        boolean updateResult = updateById(item);

        // 6. 记录操作日志
        if (updateResult) {
            operationLogService.saveMaterialLog(
                    originalItem.getListId(),
                    "物料[" + originalItem.getMaterialName() + "]",
                    operatorId,
                    operatorName,
                    "ITEM_UPDATE",
                    buildItemJson(originalItem),
                    buildItemJson(item),
                    "更新物料条目信息"
            );

            // 7. 重新计算清单汇总
            materialListService.calculateListSummary(originalItem.getListId());
        }

        return updateResult;
    }

    @Transactional
    @Override
    public boolean deleteMaterialItem(Long itemId, Long operatorId, String operatorName) {
        if (itemId == null) {
            throw new ServiceException("物料条目ID不能为空");
        }

        // 1. 查询原数据
        PmMaterialItem item = getById(itemId);
        if (item == null) {
            throw new ServiceException("物料条目不存在（ID：" + itemId + "）");
        }

        // 2. 校验清单状态
        PmMaterialList materialList = materialListService.getById(item.getListId());
        if (materialList != null && materialList.getListStatus() >= 2) {
            throw new ServiceException("清单已推送或已确认，不允许删除物料条目");
        }

        // 3. 执行逻辑删除
        boolean deleteResult = removeById(itemId);

        // 4. 记录操作日志
        if (deleteResult) {
            operationLogService.saveMaterialLog(
                    item.getListId(),
                    "物料[" + item.getMaterialName() + "]",
                    operatorId,
                    operatorName,
                    "ITEM_DELETE",
                    buildItemJson(item),
                    null,
                    "删除物料条目"
            );

            // 5. 重新计算清单汇总
            materialListService.calculateListSummary(item.getListId());
        }

        return deleteResult;
    }

    @Transactional
    @Override
    public boolean batchDeleteMaterialItems(List<Long> itemIds, Long operatorId, String operatorName) {
        if (CollectionUtils.isEmpty(itemIds)) {
            throw new ServiceException("物料条目ID列表不能为空");
        }

        // 1. 查询所有要删除的条目
        List<PmMaterialItem> items = listByIds(itemIds);
        if (CollectionUtils.isEmpty(items)) {
            throw new ServiceException("未找到要删除的物料条目");
        }

        // 2. 校验清单状态
        Long listId = items.get(0).getListId();
        PmMaterialList materialList = materialListService.getById(listId);
        if (materialList != null && materialList.getListStatus() >= 2) {
            throw new ServiceException("清单已推送或已确认，不允许删除物料条目");
        }

        // 3. 执行批量逻辑删除
        boolean deleteResult = removeByIds(itemIds);

        // 4. 记录操作日志
        if (deleteResult) {
            StringBuilder itemNames = new StringBuilder();
            for (PmMaterialItem item : items) {
                if (itemNames.length() > 0) {
                    itemNames.append("、");
                }
                itemNames.append(item.getMaterialName());
            }

            operationLogService.saveMaterialLog(
                    listId,
                    "批量删除物料",
                    operatorId,
                    operatorName,
                    "ITEM_BATCH_DELETE",
                    "{\"item_ids\":" + itemIds + ",\"item_names\":\"" + itemNames + "\"}",
                    null,
                    "批量删除" + items.size() + "条物料条目：" + itemNames
            );

            // 5. 重新计算清单汇总
            materialListService.calculateListSummary(listId);
        }

        return deleteResult;
    }

    // 辅助方法：查找组内已确认条目
    private PmMaterialItem findConfirmedItem(List<PmMaterialItem> items) {
        return items.stream()
                .filter(item -> item.getIsBudgetConfirmed() == 1)
                .findFirst()
                .orElse(null);
    }

    // 辅助方法：构建物料条目的JSON字符串用于日志记录
    private String buildItemJson(PmMaterialItem item) {
        if (item == null) {
            return "{}";
        }
        return String.format(
                "{\"id\":%d,\"material_name\":\"%s\",\"spec\":\"%s\",\"material_quantity\":%s,\"user_view_price\":%s,\"cost_price\":%s,\"budget_type\":%d}",
                item.getId(),
                item.getMaterialName() != null ? item.getMaterialName() : "",
                item.getSpec() != null ? item.getSpec() : "",
                item.getMaterialQuantity() != null ? item.getMaterialQuantity() : "null",
                item.getUserViewPrice() != null ? item.getUserViewPrice() : "null",
                item.getCostPrice() != null ? item.getCostPrice() : "null",
                item.getBudgetType() != null ? item.getBudgetType() : 0
        );
    }
}
